﻿using MaterialDesignThemes.Wpf;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Media;
using UIWindow.DeviceCommunications;
using UIWindow.Domains;
using UIWindow.Enums;
using UIWindow.GlobalParameters;
using UIWindow.Helper;
using UIWindow.Lucifer;
using UIWindow.Models;
using UIWindow.Models.S7NET;
using UIWindow.Protocols.Fins;
using System.IO.Ports;
using UIWindow.Services.Context;
using System.Diagnostics;

namespace UIWindow.Services
{
    public class TaskService
    {
        private string _barcode;
        private SerialPort _serialPort;
        private CancellationTokenSource _taskToken;
        private DeviceGlobal _deviceGlobal;
        private ParameterGlobal _parameter;
        private MainGlobal _mainGlobal;
        private HomePageGlobal _pageGlobal;
        private UserGlobal _userGlobal;
        private Brush _runOne = new SolidColorBrush(Color.FromArgb(0xFF, 0x41, 0x9E, 0x00));
        private Brush _runTwo = new SolidColorBrush(Color.FromArgb(0xFF, 0x93, 0xFF, 0x48));
        //private IPolymorphicEventManagement _polymorphic;

        public TaskService(ParameterGlobal parameter, DeviceGlobal deviceGlobal, MainGlobal mainGlobal, HomePageGlobal pageGlobal, UserGlobal userGlobal)
        {
            _parameter = parameter;
            _deviceGlobal = deviceGlobal;
            _taskToken = new CancellationTokenSource();
            _mainGlobal = mainGlobal;
            _pageGlobal = pageGlobal;
            _userGlobal = userGlobal;
            //_polymorphic = PolymorphicEventManagement.GetObject();
        }

        /// <summary>
        /// 停止
        /// </summary>
        public void Stop() {
            if(_serialPort != null && _serialPort.IsOpen) _serialPort.Close();
            _taskToken.Cancel();
        }

        /// <summary>
        /// 启动
        /// </summary>
        public async Task<bool> SwitchOn()
        {
            if (_taskToken.Token.IsCancellationRequested) _taskToken = new CancellationTokenSource();
            if (await DeviceLink())
            {
                try
                {
                    if (_serialPort == null)
                    {
                        var serialPortObject = _deviceGlobal.DeviceList.FirstOrDefault(x => x.IsSocket == false && x.Types == DeviceType.手持扫码);
                        _serialPort = new SerialPort(serialPortObject.IPofCom, serialPortObject.Port, Parity.None, 8, StopBits.One);
                        _serialPort.ReadTimeout = 3000;
                        _serialPort.WriteTimeout = 3000;
                        _serialPort.DataReceived += SerialPort_DataReceived;
                        _serialPort.Open();
                    }
                    else _serialPort.Open();
                }
                catch (Exception ex)
                {
                    $"扫码枪串口打开失败 {ex.Message}".MessageDialogsUI(MessageLevelType.Error);
                    return false;
                }
                foreach (var item in _deviceGlobal.DeviceList)
                {
                    if (!_mainGlobal.DeviceLinkList.Any(k => k.DeviceName == item.Types.ToString())) _mainGlobal.DeviceLinkList.Insert(0, new DeviceStatusModel() { DeviceName = item.Types.ToString(), Status = Brushes.Green });
                }
                TaskManager.RemoveAll();
                _ = Task.Run(() =>
                {
                    int count = 0;
                    ushort buffer = 0;
                    Stopwatch stopwatch = new Stopwatch();
                    stopwatch.Restart();
                    var tcp = _deviceGlobal.DeviceList.Where(x => x.Types == DeviceType.注液机).FirstOrDefault().Comm;
                    S7CMDModel s7 = null;
                    while (!_taskToken.Token.IsCancellationRequested)
                    {
                        try
                        {
                            s7 = tcp.ReadWrite<S7CMDModel>(new S7ParamModel() { Address = 0 });
                            if (_taskToken.Token.IsCancellationRequested) break;
                            if (s7 == null) continue;
                            if (buffer != s7.DeviceStatus || stopwatch.ElapsedMilliseconds >= 300000)
                            {
                                //设备状态上传
                                stopwatch.Restart();
                                if (_parameter.DecideParameter.EnableMES)
                                {
                                    MyMesHelper.DeviecStatus(_parameter.RunParameter.EquipNum,
                                        s7.DeviceStatus,
                                        DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
                                        DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), "",
                                        _userGlobal.LoginUser.Name).ConfigureAwait(false);
                                }
                            }
                            buffer = s7.DeviceStatus;
                            if (s7.BeforeCodeStart == 1)
                            {
                                TaskManager.Publish(new ScanCodeContext()
                                {
                                    AddressSignal = 2,
                                    AddressBarCode = 10,
                                    Types = TaskTypes.前扫码,
                                    BarCode = null,
                                });
                            }
                            if (s7.BeforeWeight == 1)
                            {
                                TaskManager.Publish(new WeighingContext()
                                {
                                    BarCode = Encoding.ASCII.GetString(s7.BarCodeByte.Skip(2).Take(s7.BarCodeByte[1]).ToArray()),
                                    Types = TaskTypes.前称重,
                                    AddressSignal = 4,
                                    AddressComplete = 111,
                                    StationNo = s7.StationNo,
                                    CupNumber = s7.CupNumber,
                                    Cycles = s7.Cycles,
                                    NegativePressure = s7.NegativePressure,
                                    PositivePressure = s7.PositivePressure,
                                    VacuumBeforeFilling = s7.VacuumBeforeFilling,
                                    VacuumBeforeReturningHelium = s7.VacuumBeforeReturningHelium,
                                    VacuumDegreeAfterReturningHelium = s7.VacuumDegreeAfterReturningHelium,
                                    VacuumDuringFilling = s7.VacuumDuringFilling,
                                    //AddressInjection = 106,
                                    AddressInjection = 126,
                                    TimePositivePressure = s7.TimePositivePressure,
                                    TimeNegativePressure = s7.TimeNegativePressure,
                                    TimePositivePressureSetting=s7.TimePositivePressureSetting,
                                    TimeNegativePressureSetting = s7.TimeNegativePressureSetting,
                                    PositivePressureSetting=s7.PositivePressureSetting,
                                    NegativePressureSetting=s7.NegativePressureSetting,
                                    VacuumBeforeFillingSetting = s7.VacuumBeforeFillingSetting,
                                    VacuumDuringFillingSetting= s7.VacuumDuringFillingSetting
                                });
                            }
                            if (s7.BeforeWeightClear == 1)
                            {
                                TaskManager.Publish(new WeightClearContext()
                                {
                                    AddressSignal = 6,
                                    Types = TaskTypes.前称重,
                                    AddressComplete = 11,
                                });
                            }
                            if (s7.BumpPARASendCMD == 1)
                            {
                                //InjectionModel injection = tcp.ReadWrite<InjectionModel>(new S7ParamModel() { Address = 110 });
                                InjectionModel injection = tcp.ReadWrite<InjectionModel>(new S7ParamModel() { Address = 130 });
                                TaskManager.Publish(new InjectionPumpParametersContext()
                                {
                                    BarCode = Encoding.ASCII.GetString(injection.BarCode.Skip(2).Take(s7.BarCodeByte[1]).ToArray()),
                                    Types = TaskTypes.注液泵,
                                    AddressSignal = 8,
                                    AddressComplete = 96,
                                    AddressResults = 98,
                                    注液量 = injection.InjectionValue,
                                });
                            }
                            count++;
                            if (count > 20)
                            {
                                count = 0;
                                if (_pageGlobal.HomeProperty.RunForeroud == _runOne) _pageGlobal.HomeProperty.RunForeroud = _runTwo;
                                else _pageGlobal.HomeProperty.RunForeroud = _runOne;
                                //if (!tcp.Write(new S7ParamModel() { Address = 8714, Value = new byte[] { 0x00, 0x01 } })) "心跳写入失败".RunLog(MessageLevelType.Warning);
                            }
                            Thread.Sleep(_parameter.RunParameter.PLCTime);
                            while (!tcp.IsConnect && !_taskToken.Token.IsCancellationRequested)
                            {
                                Thread.Sleep(_parameter.RunParameter.PLCTime);
                            }
                        }
                        catch (Exception ex)
                        {
                            $"读取PLC信号异常：{ex.Message}".RunLog(MessageLevelType.Info);
                        }
                    }
                }, _taskToken.Token).ContinueWith(sender =>
                {
                    _mainGlobal.SocketToken.Cancel();
                    Bootstrapper.UISynchronize(() => _mainGlobal.DeviceLinkList.Clear());
                    _pageGlobal.HomeProperty.RunForeroud = Brushes.Black;
                    foreach (var item in _deviceGlobal.DeviceList)
                    {
                        if (item.Comm != null)
                        {
                            try { item.Comm.Close(); }
                            catch (Exception) { }
                            item.Comm = null;
                        }
                    }
                    _serialPort.Close();
                    Bootstrapper.UIAsync(k => {
                        if (DialogHost.IsDialogOpen("RootDialog")) DialogHost.Close("RootDialog");
                    }, null);
                });
                return true;
            }
            foreach (var item in _deviceGlobal.DeviceList)
            {
                if (item != null)
                {
                    try { item.Comm.Close(); }
                    catch (Exception) { }
                    item.Comm = null;
                }
            }
            _mainGlobal.SocketToken.Cancel();
            _mainGlobal.DeviceLinkList.Clear();
            return false;
        }

        private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            if (_serialPort.BytesToRead > 1)
            {
                byte[] bytes = new byte[1024];
                int length = _serialPort.Read(bytes, 0, 1024);
                _barcode = Encoding.ASCII.GetString(bytes.Take(length).ToArray()).Trim();
                $"手持扫码枪条码：{_barcode}".RunLog(MessageLevelType.Info);
                TaskManager.Publish(new ScanCodeContext()
                {
                    AddressSignal = 0,
                    AddressBarCode = 10,
                    Types = TaskTypes.前扫码,
                    BarCode = _barcode,
                });
            }
        }

        public async Task<bool> DeviceLink()
        {
            if (_mainGlobal.SocketToken.Token.IsCancellationRequested) _mainGlobal.SocketToken = new CancellationTokenSource();
            return await Task.Run(() => Parallel.ForEach(_deviceGlobal.DeviceList, (x, _parallelLoopState) =>
             {
                 if (x.Index == 999) return;
                 ICommunication model = null;
                 if (x.IsSocket)
                 {
                     if (x.Types == DeviceType.注液机)
                     {
                         model = new CommS7(x.IPofCom);
                     }
                     else
                     {
                         model = new CommTCP(x.IPofCom, x.Port, x.Index);
                     }
                 }
                 //else
                 //{
                 //    return;
                 //    model = new CommSerialPort(x.IPofCom, x.Port, x.Index);
                 //}
                 model.DropAlarms += Device_DropAlarms;
                 if (model.Connect())
                 {
                     if (x.Types == DeviceType.前称重 || x.Types == DeviceType.后称重) model.Read(_mainGlobal.SocketToken);
                     if (x.Types == DeviceType.注液泵)
                     {
                         model.Write(new FinsHandshakePackage() { Address = (byte)_parameter.RunParameter.FinsIP });
                         Thread.Sleep(20);
                         var shakeHands = new ResponseShakeHands().Handle(model.Read());
                         if (shakeHands != null) x.DA1 = (byte)(shakeHands as ResponseShakeHands).ServerAddress;
                         else throw new Exception("通信异常");
                     }
                     x.Comm = model;
                 }
                 else
                 {
                     $"设备[{x.Types}]-[{x.IPofCom}]：[{x.Port}] 连接失败".RunLog(MessageLevelType.Error);
                     _parallelLoopState.Stop();
                 }
             }).IsCompleted);
        }

        private bool Device_DropAlarms(string ipcom, int port, int index, string message)
        {
            int count = 1;
            DeviceModel device = _deviceGlobal.DeviceList.FirstOrDefault(t => t.IPofCom == ipcom & t.Index == index & t.Port == port);
            var model = _mainGlobal.DeviceLinkList.FirstOrDefault(x => x.DeviceName == device.Types.ToString());
            if (model != null) Bootstrapper.UISynchronize(() => model.Status = Brushes.Yellow);
            device.Comm.Close();
            while (!device.Comm.Connect())
            {
                if (_mainGlobal.SocketToken.Token.IsCancellationRequested) return false;
                $"{device.Types} {ipcom} {index} 掉线重连".RunLog(MessageLevelType.Warning);
                Thread.Sleep(count * 500);
                count++;
                if (count > _parameter.RunParameter.ScalesNumberReconnections && device.Types != DeviceType.注液机)
                {
                    count = 1;
                    //像PLC写入报警信息

                }
                if (device.Comm != null) device.Comm.Close();
                else return false;
            }
            if (device.Types == DeviceType.注液泵)
            {
                device.Comm.Write(new FinsHandshakePackage() { Address = (byte)_parameter.RunParameter.FinsIP });
                Thread.Sleep(20);
                var shakeHands = new ResponseShakeHands().Handle(device.Comm.Read());
                if (shakeHands != null) device.DA1 = (byte)(shakeHands as ResponseShakeHands).ServerAddress;
            }
            if (model != null) Bootstrapper.UISynchronize(() => model.Status = Brushes.Green);
            $"{device.Types} {ipcom} {index} 重连成功".RunLog(MessageLevelType.Info);
            return true;
        }
    }
}
